package yao.guava.function;

import java.util.HashMap;

import org.junit.Test;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;

/**
 * 函数式编程是一种历久弥新的编程范式，比起命令式编程，它更加关注程序的执行结果而不是执行过程
 * TIP:Java 始终是一个面向对象（命令式）的语言，在我们使用函数式编程这种黑魔法之前，
 * 需要确认：同样的功能，使用函数式编程来实现，能否在健壮性和可维护性上，超过使用面向对象（命令式）编程的实现？
 * @author chenyao
 */
public class FunctionTest {

	@Test
	public void testFunction() {
		//接口限制只能接收一个参数，如果多个参数可以封装成对象或者使用数组来跳过限制
		// 泛型，第一个为输入，第二个为输出
		Function<Double, Double> sqrt = new Function<Double, Double>() {
		    public Double apply(Double input) {
		        return Math.sqrt(input);
		    }
		};
		System.out.println(sqrt.apply(1024.0));//2.0
	}
	
	//Functions 是 Guava 中与 Function 接口配套使用的工具类，为处理实现了 Function 接口的仿函数提供方便
	//Functions 是一个方法工厂，提供各种返回 Function 实例的方法。如果我们把 Function 视为函数，那么 Functions 的方法就是高阶函数，因为它能够将函数作为它的返回值。
	@Test
	public void testFunctions() {
		//1.toStringFunction
		//根据toStringFunction 创建模式学习其创建思想（参考其源码）
		String apply = Functions.toStringFunction().apply(1.89);
		System.out.println(apply);
		//2.ConstantFunction 返回一个常量
		Integer apply2 = Functions.constant(1).apply(null);
		System.out.println(apply2);
		
		//compose  组合 x->y y->z ==> x->z  g.apply(f.apply(a));
		Function<Integer, Double> compose = Functions.compose(new Function<Double, Double>() {
		    public Double apply(Double input) {
		        return Math.sqrt(input);
		    }
		}, new Function<Integer, Double>() {
			@Override
			public Double apply(Integer input) {
				// TODO Auto-generated method stub
				return Double.parseDouble(input.toString());
			}
		});
		System.out.println(compose.apply(2));	
	}
	
	//将其他数据结构或者接口的实例转变成 Function 实例
	@Test
	public void testFunctionsOfForMap() {
		// f(x)= map.get(x) 如果没有该key抛异常
		//System.out.println(Functions.forMap(new HashMap<String, String>()).apply("1"));
		//f(x)= map.get(x) 如果没有该key 返回设置的默认值
		System.out.println(Functions.forMap(new HashMap<String, String>(), null).apply("1"));

	}
	
	@Test
	public void testFunctionsOfForPredicate() {
		//ForPredicate 前置条件校验 
		//  柯里化技术
		Function<Integer, Predicate<String>> lessThan = new Function<Integer, Predicate<String>>() {
			@Override
			public Predicate<String> apply(final Integer input) {
				return new Predicate<String>() {
					@Override
					public boolean apply(String str) {
						return str.length() < input;
					}
				};
			}			
		};
		boolean isLessThan10 = lessThan.apply(10).apply("lessThan10");
		System.out.println(isLessThan10);
	}
}
